import traceback

from HeaderParser import *
import socket
import threading

PORT = 8080


class ServerThread(threading.Thread):
    """
    请求处理线程
    新建一个线程来处理当前的请求
    """

    def __init__(self, accept: socket.socket):
        """
        用socket.accept 连接上后得到对应对象然后继续处理
        :param accept:
        """
        super().__init__()
        self.header = None
        self.content = None
        self.accept = accept

    def http_handler(self):
        res = bytes()
        content_length = 2000  # 请求头应在1000byte以内
        while True:
            new = self.accept.recv(100)
            res = res + new
            if "\r\n\r\n".encode() in res and self.header is None:
                self.header = HttpRequestHeader(res)
                res = res.split('\r\n\r\n'.encode())[1]
                if 'Content-Length' in self.header.header.keys():
                    content_length = int(self.header.header['Content-Length'])
                else:
                    content_length = 0
            if len(res) >= content_length:
                self.content = res
                break
        print("header:\n", self.header)
        print('content:\n', self.content)
        if self.content:
            self.content = ContentParser(_type=self.header.header['Content-Type'], _bytes=self.content).get_data()
        print('content:\n', self.content)
        response_maker = RequestHandler.handle_request(header=self.header, content=self.content)
        self.send_response(response_maker.get_response())
        self.accept.close()

    def send_response(self, _data: bytes):
        self.accept.send(_data)

    def run(self):
        self.http_handler()


class RequestHandler:
    """
    请求处理，有路径表，可有外部增添处理函数，由serverThread查表调用
    用户只要继承该类并编写响应的方法即可
    """

    __handler_list = []
    __handler_path = []
    __default_path = []
    __default_method = []

    def __init__(self, path: str, method: str):
        RequestHandler.__handler_list.append(self)
        RequestHandler.__handler_path.append((path, method))

    @abc.abstractmethod
    def handler(self, _request: tuple):
        """
        子类重写该方法
        :param _request: (header, content)
        :return:
        """
        pass

    @classmethod
    def handle_request(cls, header, content):
        """
        请求处理，由请求处理线程调用
        :param header: HttpRequestHeader
        :param content: 未定
        :return:
        """
        path = header.path
        method = header.method

        if (path, method) in cls.__handler_path:  # 先检查设定处理表
            return HttpResponseMaker(_code=200, _status='OK',
                                     _data=cls.__handler_list[cls.__handler_path.index((path, method))].handler(
                                         (header, content)))
        else:  # 检查默认处理路由表
            for index, start_path in enumerate(cls.__default_path):
                if path.startswith(start_path) and method in cls.__default_method[index]:
                    return cls.__default_handler(path, method, content)
        return HttpResponseMaker(_code=404, _status="NotFound")

    @classmethod
    def set_default_handler(cls, path: str, method_list: tuple):
        """
        设置默认请求路径处理内容，可以直接完成简单的GET
        DELETE,SET,PUT 可能在后期实现
        :param path: 路径前缀
        :param method_list: 请求方法
        :return:
        """
        cls.__default_path.append(path)
        cls.__default_method.append(method_list)

    @classmethod
    def __default_handler(cls, path, method, content):
        print("default handler")
        if method == "GET":
            try:
                rp_data = FileResponseData(path)
                return HttpResponseMaker(_code=200, _status="OK", _data=rp_data)
            except Exception as error:
                traceback.print_exc()
                return HttpResponseMaker(_code=500, _status="ServerError")


def run_server():
    """
    运行服务器
    :return:
    """
    s = socket.socket()
    host = socket.gethostname()
    print("host:", host)
    print("port:", PORT)
    s.bind((host, PORT))
    s.listen(5)
    while True:
        print("开始监听")
        acc, addr = s.accept()
        print('连接地址', addr)
        ServerThread(acc).start()


if __name__ == '__main__':
    RequestHandler.set_default_handler("/test", tuple(["GET"]))
    run_server()
